<?php
// +----------------------------------------------------------------------
// | 杭州十禾信息科技有限公司
// +----------------------------------------------------------------------
// | Copyright (c) 2013-2015 http://www.shelpe.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: LeePuman <ysyzlsm@163.com>
// +----------------------------------------------------------------------

/**
 * 类目Model. 该类设计到多个表. categories表是taobao.ttopcates.get获取到的热门类目.
 * tb_cates, tb_cates_prop, tb_cates_propvalue是淘宝全类目.
 * 
 * @author weiping
 *
 */
class CategoryModel extends NewzanModel {
	
	protected $tableName = 'categories';
	/** @var Model */
	protected $_tbCateMdl = null;
	
	/**
	 * 得到某个类目的基础统计属性
	 * @param string $ids , 类目id值，多个类目id用逗号隔开
	 */
	public function getCatBase($ids){
	   $params = array(
	       'category_ids' => $ids,
	       'time' => 'WEEK',
	       'filter' => 'PV,CLICK,AVGCPC,COMPETITION,CTR'
	   );
	   $resp = $this->_api->SimbaInsightCatsbaseGetRequest($params);
	   return $resp;
	}

	public function getCatBaseAvg($cateId, $maxDays = 3){
		if(!$cateId)
			return array();
		$skey = "cAvg-$cateId-$maxDays";
		$avg = S($skey);
		if($avg) 
			return $avg;
		
		$fields = array('pv', 'click', 'avg_price', 'competition', 'ctr'); // 这个是返回结果的字段. 与给的参数字段中的AVGCPC不一致.
		$params = array(
				'category_ids' => $cateId,
				'time' => 'WEEK',
				'filter' => 'PV,CLICK,AVGCPC,COMPETITION,CTR'
		);
		$resp = $this->_api->SimbaInsightCatsbaseGetRequest($params);
		$res = object_to_array($resp);
		
		$avg = array();
		$dataList = array();
		if(isset($res['in_category_bases']['i_n_category_base'][0]['in_record_base_list']['i_n_record_base'])) {
			$dataList = $res['in_category_bases']['i_n_category_base'][0]['in_record_base_list']['i_n_record_base'];
			$days = 0;
			foreach($dataList as $record) {
				foreach($record as $field => $val) {
					if($field != 'date') {
						$avg[$field] += $val;
					}
				}
				++$days;
				if($days == $maxDays) 
					break;
			}
			
			foreach ($fields as $field) {
				$avg[$field] = $days > 0 ? $avg[$field] / $days : 0;
			}
			$avg['ctr'] = $avg['pv'] == 0 ? 0 : 100* $avg['click'] / $avg['pv'];
		} 
		if($dataList && substr($dataList[0]['date'], 0 , 10) == date('Y-m-d', time() - 86400)) { // 得到昨天数据了
			cache_till($skey, $avg, 7); // 保存到明天早上
		} else { // 还没有昨天的数据, 只缓存半个小时
			S($skey, $avg, 1800);
		}
		return $avg;
	}
	
	/**
	 * 根据ID查询taobao类目. 
	 * 
	 * @param int $cateId
	 * @return array 返回淘宝类目表tb_cates的一条记录. 字段有: cid, parent_cid, name, is_leaf, sort_order, feature_list, modified_time.
	 */
	public function getCategory($cateId) {
		return $this->_getTbCategoryMdl()->where(array('cid'=>$cateId))->find();
	}
	
	/**
	 * 根据类目ID获取类目名.
	 * @param int $cateId 类目ID
	 * @return string 类目名, 如果没有找到, 返回空字符串''.
	 */
	public function getCateName($cateId) {
		$res = $this->_getTbCategoryMdl()->where(array('cid'=>$cateId))->getField('name');
		return $res ? $res : '';
	}
	
	/**
	 * 保存类目的热词。每个类目有$batchSize个热词，依次排列。$cateIds中第N个类目
	 * 对应$words第N个$batchSize的热词。
	 * 
	 * @param array(int) $cateIds 类目列表。
	 * @param arrry(string) $words 热词列表。热词的数目=类目数目×$batchSize。
	 */
	public function saveCateHotWords($cateIds, $words, $time, $batchSize) {
		$len = count($cateIds);
		for($i = 0; $i < $len; ++$i) {
			$currCateId = $cateIds[$i];
			$currWords = array_slice($words, $i * $batchSize, $batchSize);
			
			// 同时写入mysql。只保存类目当前热词。没有存档。
			$data['words'] = join(',', $currWords);
			$data['words_num'] = count($currWords);
			$data['words_update_times'] = array('exp','words_update_times+1');
			if($data['words_num'] == $batchSize) {
				$data['words_full_times'] = array('exp','words_full_times+1');// 满关键词计数+1
			}
			$this->where("id=$currCateId")->save($data);
		}
	}
	
	/**
	 * 同步顶级目录
	 * @return boolean
	 */
	public function syncTopCates($force_sync = false) {
		if(!SyncModel::checkSyncStatus($user_id , 'topcate', 24 * 3600) && !$force_sync) {
			return true;
		}
		$apiMdl = new ApiModel();
		$cates = $apiMdl->getTopCates();
		if($cates) {
			$this->saveTopCates($cates);
			SyncModel::setLatestUpdated(0, 'topcate');
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 保存从API获取得到的所有类目
	 * @param object $cates 淘宝API（taobao.simba.insight.toplevelcats.get）返回的JSON对象结果。
	 */
	public function saveTopCates($cates) {
// 		$this->where(' id > 0')->save(array('deleted' => 1));
		
		$newCateIds = array();
		$topCates = $cates->in_category_tops->i_n_category_top;
		$this->startTrans();
		try {
			foreach($topCates as $topCate) {
				// echo  '+' . $topCate->category_id . ' - ' . $topCate->category_name . '</br>';
				$newCateIds[] = $topCate->category_id;
				$this->saveCateInfo($topCate, 1, 0); // 基本信息
				
				foreach($topCate->category_child_top_list->i_n_category_child_top as $subCate) {
					// echo '|---' . $subCate->category_id . ' = ' . $subCate->category_name . '</br>';
					$newCateIds[] = $subCate->category_id;
					$this->saveCateInfo($subCate, 2, $topCate->category_id); // 基本信息
				}
			}
			// 删掉不再存在的类目
			$this->where(array('id' => array('not in', $newCateIds)))->save(array('deleted' => 1));
			$this->commit();
			return true;
		} catch (Exception $e) {
			$this->rollback();
			Log::record($e->getMessage());
			Log::record($e->getTraceAsString());
			return false;
		}
	}

	/**
	 * 保存类目的一般信息。
	 * @param object $cate 类目对象：{category_id: XX, category_name: XX}
	 * @param int $level 类目层级。顶级为1，子类目逐级+1。
	 * @param int $parent 父类目的ID。
	 */
	private function saveCateInfo($cate, $level, $parent) {
		$data = array(
				'id' => $cate->category_id,
				'name' => $cate->category_name,
				'level' => $level,
				'parent' => $parent,
				'deleted' => 0,
		);
		$this->addAllOnDupUpdate(array($data));
	}
	
	/**
	 * 获取所有类目ID。
	 * 
	 * @param bool $order	是否进行排序。如果true，经常能获取全关键词的类目将排在前面。
	 * @param bool $continueLastRun	是否继续上次中断的循环。如果true，则检查上次上次是否有中断。
	 * 						如果有中断，则查询上次剩下的；否则返回全部。
	 * @return array(int)	ID数组。
	 */
	public function getAllCateIds($order = true, $continueLastRun = true) {
		$interrupted = false; // 上次是否中断
		$lastRun = $this->max('words_update_times');
		if($continueLastRun) {
			$interrupted = $this->where("words_update_times<$lastRun")->limit(1)->getField('id');
		}
		if(!$interrupted) {
			if(!$order) {
				return $this->getField('id', true);
			} else {
				return $this->order('words_num DESC')->getField('id', true);
			}
		} else {
			if(!$order) {
				return $this->where("words_update_times<$lastRun")->getField('id', true);
			} else {
				return $this->where("words_update_times<$lastRun")->order('words_num DESC')->getField('id', true);
			}
		}
	}
	
	/**
	 * 查询某个类目下的所有或者某个基础属性的最大值. 
	 * 
	 * @param int $cateId	要查询的类目ID
	 * @param string $prop	要查询的基础属性. 如果不给定 则查询所有基础属性.
	 * @return array|double 获得的最大值数组或者单个值.
	 */
	public function maxProps($cateId, $fields = array() ) {
	    $default_fields =  array( 'pv' , 'click' , 'avg_price' , 'ctr' , 'competition');
	    if( empty( $fields ) ) $fields = $default_fields;
	    if( !is_array($fields) ) $fields = explode(',' , $fields);
	    $fields = array_intersect( $default_fields , $fields);
	    $db_table = 'ztc_words.word_cats';
        $sql_max = 'select
                    			max(pv) as pv , 
                    			max(competition) as competition, 
                    		    max(click) as click,
                    			max(ctr) as ctr,
                    			max(avg_price) as avg_price
                            from ' . $db_table . '
                            where category_id = ' . $cateId ;
        $max_value = M(  )->query($sql_max);
        $max_value = array_pop( $max_value );
        $data = array();
        foreach( $fields as $field){
            $data[$field] = array(
                'max' => $max_value[$field],
                'min' => 0                   
            );
        }
        return $data;
	}
	
	/**
	 * 获取adgroup所在行业的行业数据。
	 *
	 * @param DbRow $adgroup
	 * @param array[string] $fields 要查询的列
	 * @param array[string=>int] $conditons 查询条件. 默认或者给空为一个星期内全部.
	 * @return array2d array(field => float) 注意返回的ctr和cvr是乘以了100后的不带百分号的部分. 所有的费用都是以元为单位.
	 */
	public function getIndustryAvg($adgroup, $fields, $conditons = null) {
		$cateIds = explode(' ', $adgroup['category_ids']);
		if(empty($conditons)) {
			$conditons = array('filter' => 0, 'filter_level' => 0, 'product_type'=>1, 'timespan'=>7);
		}
		//$conditons = $conditons + array('cate_id' => $cateId);
		for($i = count($cateIds) - 1; $i >= 0; --$i) {
			$conditons['cate_id'] = $cateIds[$i];
			// "cate_id=$cateId AND filter=0 AND filter_level=0 AND product_type=0 AND timespan=7"
			$industryData = M('industry_stats')->field($fields)->where($conditons)->order("crawl_date desc")->find();
			if($industryData) {
				foreach($industryData as $field => $val) {
					if(substr($field, 0, 5) == 'trend') { // 序列值求加权平均
						$decodedVal = json_decode($val);
						$sum = 0;
						$num = 0;
						foreach($decodedVal as $x => $n) {
							$sum += $x * $n;
							$num += $n;
						}
						$industryData[$field] = $num > 0 ? $sum / $num : 0;
					}
				}
				return $industryData;
			}
		}
		return null;
	}
	
	
	/**
	 * Get the leaf category ID of a adgroup.
	 * @param DbRow $adgroup
	 */
	public static function getAdgroupCate($adgroup) {
		$cateIds = explode(' ', $adgroup['category_ids']);
		return array_pop($cateIds);
	}
	
	/**
	 * @return Model	表tb_cates的Thinkphp基础Model.
	 */
	private function _getTbCategoryMdl() {
		if($this->_tbCateMdl == null) {
			$this->_tbCateMdl = M('tb_cates');
		}
		return $this->_tbCateMdl;
	}
}
	